package com.cby.operation.pay.data

import android.text.TextUtils
import com.cby.operation.common.http.HttpHelper
import com.cby.operation.common.util.CbyLogUtils
import com.cby.operation.common.util.DateUtils
import com.cby.operation.common.util.HandlerUtils
import com.cby.operation.common.util.ThreadPoolUtils.execute
import com.cby.operation.pay.bean.*
import com.cby.operation.sdk.*
import com.cby.operation.sdk.SdkConfiguration.gameId
import com.cby.operation.sdk.SdkConfiguration.userId
import com.cby.operation.sdk.http.UrlHelper.authHeaders
import com.cby.operation.sdk.http.UrlHelper.buildSdkUrl
import com.cby.operation.sdk.util.VerifyUtils.getVerifySign
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.lang.ref.WeakReference
import java.util.*

/**
 * 描述信息:充值API数据仓库类
 *
 * @author chenbaoyang
 * @create 2021/8/3
 */
object PayApiRepository {

    private const val TAG = "Pay"
    private const val PAY_CONFIG_PATH = "pay/config"
    private const val PAY_SUBMIT_PATH = "pay/submit"


    /**
     * 支付配置接口
     */
    private val BASE_PAY_CONFIG_URL = buildSdkUrl("pay/config")

    /**
     * 支付下单接口
     */
    private val BASE_PAY_SUBMIT_URL = buildSdkUrl("pay/submit")

    /**
     * 订单查询接口
     */
    private val BASE_ORDER_QUERY_URL = buildSdkUrl("pay/search")



    private lateinit var payConfigReference: WeakReference<OnPayConfigCallBack>
    private lateinit var SubmitOrderReference: WeakReference<OnSubmitOrderCallBack>

    /**
     * 获取支付配置
     *
     * @param callBack
     */
    fun loadPayConfig(callBack: OnPayConfigCallBack) {
        payConfigReference = WeakReference(callBack)
        execute {
            val timeStamp = System.currentTimeMillis()
            val sign = getVerifySign(gameId, userId, PAY_CONFIG_PATH, timeStamp.toString())
            val param: MutableMap<String, Any> = HashMap()
            param[KEY_GAME_ID] = gameId
            param[KEY_TIME_STAMP] = timeStamp
            param[KEY_SIGN] = sign
            HttpHelper.requestPost(
                BASE_PAY_CONFIG_URL,
                param,
                authHeaders,
                object : HttpHelper.OnHttpRequestListener {
                    @Throws(Exception::class)
                    override fun onResponseSuccess(response: String?) {
                        try {
                            if (TextUtils.isEmpty(response)) {
                                onResponseError(
                                    ERR_CODE_SERVER_EXCEPTION,
                                    ERR_MSG_SERVER_EXCEPTION
                                )
                                return
                            }
                            parsePayConfigJson(response)
                        } catch (e: JSONException) {
                            onResponseError(ERR_CODE_SERVER_EXCEPTION, e.message)
                        }
                    }

                    override fun onResponseError(code: Int, errorMessage: String?) {
                        CbyLogUtils.e(TAG, errorMessage)
                        HandlerUtils.runOnMainThread(Runnable {
                            handlePayConfigFailed(code, errorMessage)
                        })
                    }
                })
        }
    }

    /**
     * 解析用户校验的结果
     *
     * @param response
     * @param callback
     * @throws JSONException
     */
    @Throws(JSONException::class)
    private fun parsePayConfigJson(response: String?) {
        val data = JSONObject(response)
        val code = data.optInt(KEY_RESPONSE_CODE)
        val msg = data.optString(KEY_RESPONSE_MSG)
        val dataJson = data.optJSONObject(KEY_RESPONSE_DATA)
        when (code) {
            CODE_SUCCESS -> {
                val config = PayConfig()
                config.moneyRate = dataJson.optString(KEY_RESPONSE_MONEY_RATE)
                config.moneyName = dataJson.optString(KEY_RESPONSE_MONEY_NAME)
                config.contact = dataJson.optString(KEY_RESPONSE_PAY_CONTACT)
                config.payChannels = parseChannels(
                    dataJson.optJSONArray(KEY_RESPONSE_PAY_CHANNELS)
                )
                config.payRetries = parseChannels(
                    dataJson.optJSONArray(KEY_RESPONSE_PAY_RETRIES)
                )
                handlePayConfigOK(config)
            }
            CODE_PAY_MAINTENANCE -> {
                val maintenanceContent = dataJson.optString(
                    KEY_RESPONSE_MAINTENANCE_CONTENT
                )
                handlePayConfigFailed(code, maintenanceContent)
            }
            else -> {
                handlePayConfigFailed(code, msg)
            }
        }
    }

    /**
     * 解析支付渠道文案
     *
     * @param jsonArray JSONArray?
     * @return List<String>?
     */
    private fun parseChannels(jsonArray: JSONArray?): List<String>? {
        if (jsonArray == null) {
            return null
        }
        val tips: MutableList<String> = ArrayList()
        val len = jsonArray.length()
        for (i in 0 until len) {
            tips.add(jsonArray.optString(i))
        }
        return tips
    }


    /**
     * 处理支付配置加载成功的回调
     *
     * @param config PayConfig [PayConfig]
     */
    private fun handlePayConfigOK(config: PayConfig?) {
        payConfigReference.get()?.onResponseOk(config)
    }

    /**
     * 处理支付配置加载失败的回调
     * @param code Int
     * @param message String?
     */
    private fun handlePayConfigFailed(code: Int, message: String?) {
        payConfigReference.get()?.onResponseFailed(code, message)
    }




    /**
     * 支付下单
     */
    fun submitOrder(
        cpOrderId: String, userName: String, money: Int,
        goodsName: String, server: Int, ext: String?, payType: String,
        callBack: OnSubmitOrderCallBack?
    ) {
        execute(Runnable {
            val timeStamp = System.currentTimeMillis()
            val sign = getVerifySign(gameId, userId, PAY_SUBMIT_PATH, timeStamp.toString())
            val param: MutableMap<String, Any> = HashMap()
            param[KEY_GAME_ID] = gameId
            param[KEY_PAY_GAME_ORDER] = cpOrderId
            param[KEY_PAY_MONEY] = money
            param[KEY_PAY_USER_NAME] = userName
            param[KEY_PAY_GAME_SERVER] = server
            param[KEY_PAY_GOODS_NAME] = goodsName
            param[KEY_PAY_TYPE] = payType
            param[KEY_PAY_EXT] = ext.toString()
            param[KEY_TIME_STAMP] = timeStamp
            param[KEY_SIGN] = sign
            HttpHelper.requestPost(
                BASE_PAY_SUBMIT_URL, param,
                authHeaders,
                object : HttpHelper.OnHttpRequestListener {

                    @Throws(Exception::class)
                    override fun onResponseSuccess(response: String?) {
                        try {
                            if (TextUtils.isEmpty(response)) {
                                onResponseError(
                                    ERR_CODE_SERVER_EXCEPTION,
                                    ERR_MSG_SERVER_EXCEPTION
                                )
                                return
                            }
                            parseOrderInfoJson(response, callBack)
                        } catch (e: JSONException) {
                            onResponseError(ERR_CODE_SERVER_EXCEPTION, e.message)
                        }
                    }

                    override fun onResponseError(code: Int, errorMessage: String?) {
                        CbyLogUtils.e(TAG, errorMessage)
                        HandlerUtils.runOnMainThread(Runnable {
                            callBack?.onResponseFailed(
                                code,
                                errorMessage
                            )
                        })
                    }
                })
        })
    }

    @Throws(JSONException::class)
    private fun parseOrderInfoJson(response: String?, callback: OnSubmitOrderCallBack?) {
        val data = JSONObject(response)
        val code = data.optInt(KEY_RESPONSE_CODE)
        val msg = data.optString(KEY_RESPONSE_MSG)
        val dataJson = data.optJSONObject(KEY_RESPONSE_DATA)
        if (code == CODE_SUCCESS) {
            val config = PayOrderInfo()
            config.orderId = dataJson.optString(KEY_RESPONSE_PAY_ORDER)
            config.payType = dataJson.optString(KEY_RESPONSE_PAY_TYPE)
            config.payParams = parsePayParams(
                dataJson.optJSONObject(KEY_RESPONSE_PAY_PARAMS), config.payType!!
            )
            callback!!.onResponseOk(config)
        } else if (code == CODE_PAY_MAINTENANCE) {
            val maintenanceContent = dataJson.optString(
                KEY_RESPONSE_MAINTENANCE_CONTENT
            )
            callback!!.onResponseFailed(code, maintenanceContent)
        } else if (code == CODE_PAY_LIMIT) {
            callback!!.onPayLimit(parsePayLimit(dataJson))
        } else {
            callback!!.onResponseFailed(code, msg)
        }
    }

    private fun parsePayParams(Json: JSONObject?, payType: String): PayOrderInfo.PayParams? {
        if (Json == null) {
            return null
        }
        val payParams = PayOrderInfo.PayParams()
        if (VALUE_PAY_CHANNEL_WECHAT_H5 == payType) {
            payParams.url = Json.optString(KEY_RESPONSE_URL)
        } else if (VALUE_PAY_CHANNEL_ALIPAY == payType) {
            payParams.params = Json.optString(KEY_RESPONSE_PARAM)
        }
        return payParams
    }

    private fun parsePayLimit(json: JSONObject?): PayLimit? {
        if (json == null) {
            return null
        }
        val payLimit = PayLimit()
        payLimit.tips = json.optString(KEY_RESPONSE_PAY_TIPS)
        payLimit.content = json.optString(KEY_RESPONSE_PAY_LIMIT_CONTENT)
        payLimit.linkInfo = parseLink(
            json.optJSONObject(KEY_RESPONSE_PAY_LIMIT_LINK)
        )
        payLimit.buttonInfoList = parseButtons(
            json.optJSONArray(KEY_RESPONSE_PAY_LIMIT_BUTTONS)
        )
        return payLimit
    }

    private fun parseLink(linkJson: JSONObject?): LinkInfo? {
        if (linkJson == null) {
            return null
        }
        val name = linkJson.optString(KEY_RESPONSE_PAY_LIMIT_NAME)
        val url = linkJson.optString(KEY_RESPONSE_PAY_LIMIT_URL)
        return LinkInfo(name, url, "")
    }

    private fun parseButtons(jsonArray: JSONArray?): List<ButtonInfo>? {
        if (jsonArray == null) {
            return null
        }
        val buttonBeans: MutableList<ButtonInfo> = ArrayList<ButtonInfo>()
        val len = jsonArray.length()
        for (i in 0 until len) {
            val buttonJson = jsonArray.optJSONObject(i)
            val name = buttonJson.optString(KEY_RESPONSE_PAY_LIMIT_NAME)
            val func = buttonJson.optString(KEY_RESPONSE_PAY_LIMIT_ACTION)
            buttonBeans.add(ButtonInfo(name, func))
        }
        return buttonBeans
    }

    /**
     * 订单查询
     */
    fun orderQuery(orderId: String, callBack: OnOrderQueryCallBack) {
        execute(Runnable {
            val param: MutableMap<String, Any> = HashMap()
            param[KEY_GAME_ID] = gameId
            param[KEY_PAY_ORDER] = orderId
            HttpHelper.requestPost(
                BASE_ORDER_QUERY_URL, param,
                authHeaders,
                object : HttpHelper.OnHttpRequestListener {
                    @Throws(Exception::class)
                    override fun onResponseSuccess(response: String?) {
                        if (TextUtils.isEmpty(response)) {
                            onResponseError(
                                ERR_CODE_SERVER_EXCEPTION,
                                ERR_MSG_SERVER_EXCEPTION
                            )
                            return
                        }
                        val data = JSONObject(response)
                        val code = data.optInt(KEY_RESPONSE_CODE)
                        val msg = data.optString(KEY_RESPONSE_MSG)
                        callBack.onResponse(code, msg)
                    }

                    override fun onResponseError(code: Int, errorMessage: String?) {
                        callBack.onResponse(code, errorMessage)
                    }
                })
        })
    }



    interface OnPayConfigCallBack {
        fun onResponseOk(config: PayConfig?)
        fun onResponseFailed(code: Int, message: String?)
    }

    interface OnSubmitOrderCallBack {
        fun onResponseOk(orderInfo: PayOrderInfo?)
        fun onPayLimit(payLimit: PayLimit?)
        fun onResponseFailed(code: Int, message: String?)
    }

    interface OnOrderQueryCallBack {
        fun onResponse(code: Int, msg: String?)
    }
}